/*
 * Copyright 2023-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.icodening.collapse.core;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.locks.LockSupport;

/**
 * ThreadlessExecutor 类实现了 Executor 接口，这意味着它能够执行 Runnable 任务。
 * 简单的线程池实现，
 * @author icodening
 * @date 2023.05.14
 */
public class ThreadlessExecutor implements Executor {

    /**
     * 一个私有静态的最终对象，用于标识线程池是否应该停止接受新任务。
     */
    private static final Object SHUTDOWN = new Object();

    /**
     * 一个线程安全的队列，用于存储待执行的任务
     */
    private final Queue<Runnable> queue = new ConcurrentLinkedQueue<>();

    /**
     * 一个 volatile 对象引用，用于存储等待任务的线程
     */
    private volatile Object waiter;

    /**
     * 这个方法用于等待队列中的任务并执行它们。
     * 如果队列为空，当前线程将等待直到有新任务加入。如果线程被中断，将抛出 InterruptedException。
     *
     * @throws InterruptedException
     */
    public void waitAndDrain() throws InterruptedException {
        throwIfInterrupted();
        Runnable runnable = queue.poll();
        if (runnable == null) {
            waiter = Thread.currentThread();
            try {
                while ((runnable = queue.poll()) == null) {
                    LockSupport.park(this);
                    throwIfInterrupted();
                }
            } finally {
                waiter = null;
            }
        }
        do {
            runnable.run();
        } while ((runnable = queue.poll()) != null);
    }

    /**
     * 这是一个私有静态方法，用于检查当前线程是否被中断，如果是，则抛出 InterruptedException。
     *
     * @throws InterruptedException
     */
    private static void throwIfInterrupted() throws InterruptedException {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
    }

    /**
     * 这是 Executor 接口的实现，用于提交新任务。
     * 如果 waiter 不是 SHUTDOWN 对象，并且队列中有任务，它将通知等待的线程。
     * 如果任务被提交时 waiter 是 SHUTDOWN，并且任务被成功移除，将抛出 RejectedExecutionException。
     *
     * @param runnable the runnable task
     */
    @Override
    public void execute(Runnable runnable) {
        queue.add(runnable);
        if (waiter != SHUTDOWN) {
            LockSupport.unpark((Thread) waiter);
        } else if (queue.remove(runnable)) {
            throw new RejectedExecutionException();
        }
    }

    /**
     * 这个方法用于关闭执行器，设置 waiter 为 SHUTDOWN 并执行队列中的所有剩余任务。
     */
    public void shutdown() {
        waiter = SHUTDOWN;
        Runnable runnable;
        while ((runnable = queue.poll()) != null) {
            runnable.run();
        }
    }
}
